package com.dzx.currentency.unit2;

import com.dzx.currentency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * @author DuanZhaoXu
 * @ClassName:
 * @Description:
 * @date 2018年11月17日 14:46:52
 */
@Slf4j
@ThreadSafe
public class AtomicExample2 {

    //请求次数
    private static int clientTotal = 5000;

    //允许同时运行的线程数
    private static int threadTotal = 200;

    //计数
    //public static AtomicInteger count = new AtomicInteger(0);
    //public static AtomicLong count = new AtomicLong(0);
    /**
     * 一个或多个变量一起保持初始为零long和。 当跨线程争用更新（方法add(long) ）时，
     * 该变量集可以动态增长以减少争用。 方法sum() （或等效地， longValue() ）返回保持总和的整个变量组合的当前总和。
     * 当多个线程更新用于诸如收集统计信息，而不是细粒度同步控制的常用总和时，此类通常优于AtomicLong 。
     * 在低更新争议下，这两类具有相似的特征。 但是，在高度争议的情况下，这一类的预期吞吐量明显高于牺牲更高的空间消耗。
     *
     * LongAdders可以使用ConcurrentHashMap来维护可扩展的频率映射（直方图或多集的形式）。
     * 例如，要将一个计数添加到ConcurrentHashMap<String,LongAdder> freqs ，如果尚未存在，
     * 则可以使用freqs.computeIfAbsent(key, k -> new LongAdder()).increment();
     */
    public  static LongAdder count =  new LongAdder();
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });

        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
        log.info("count:{}", count);
    }
    private static void add() {
        count.increment();
    }
}

